﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Contracts;

namespace GBricks.Collections
{
  [Serializable]
  public class ReadOnlyHashSet<T> : ReadOnlySet<T>
  {
    private static readonly ReadOnlyHashSet<T> EmptyInstance = new ReadOnlyHashSet<T>(new HashSet<T>());

    public ReadOnlyHashSet(HashSet<T> items)
      : base(items) {
      Argument.NotNull(items, "items");
    }

    public static ReadOnlyHashSet<T> Empty {
      [DebuggerStepThrough]
      get {
        Contract.Ensures(Contract.Result<ReadOnlyHashSet<T>>() != null);
        return EmptyInstance;
      }
    }

    protected new HashSet<T> Items {
      [DebuggerStepThrough]
      get {
        Contract.Ensures(Contract.Result<HashSet<T>>() != null);
        return (HashSet<T>)base.Items;
      }
    }

    public IEqualityComparer<T> Comparer {
      [DebuggerStepThrough]
      get {
        Contract.Ensures(Contract.Result<IEqualityComparer<T>>() != null);
        return Items.Comparer;
      }
    }

    [ContractInvariantMethod]
    private void Invariant() {
      Contract.Invariant(Items != null);
      Contract.Invariant(Items.Comparer != null);
    }

    [Pure]
    public void CopyTo(T[] array) {
      Argument.NotNull(array, "array");
      Items.CopyTo(array);
    }

    [Pure]
    public void CopyTo(T[] array, int arrayIndex, int count) {
      Argument.NotNull(array, "array");
      Argument.OutOfRange(arrayIndex >= 0, "arrayIndex");
      Argument.OutOfRange(count >= 0, "count");
      Argument.OutOfRange(arrayIndex <= array.Length - count, "arrayIndex");

      Items.CopyTo(array, arrayIndex, count);
    }

    [Pure]
    public new HashSet<T>.Enumerator GetEnumerator() {
      return Items.GetEnumerator();
    }
  }
}
